//
// Created by 崔世强 on 2018/1/30.
// Copyright (c) 2018 Facebook. All rights reserved.
//

import Foundation
import UIKit
import AVFoundation
import Dispatch
import V5AMRFileCodec

protocol AudioRecordDelegate: class {
    func recordBegin()
    func recordEnd(recordPath: String,fileName:String, seconds: Double)
    func recordCanceled()
    func decibels(decibels: Float)
    func playBegin(msg:ChatMessage)
    func playEnd(_ filePath: String)
    func playInterrupted()
    func noAudioPermission()
    func recordTooShort()
}
extension AudioRecordDelegate {
    func playBegin(){}
}


class AudioRecordUtils:NSObject {
    static let instance = AudioRecordUtils()
    
    override private init() {
    }
    
    weak var delegate: AudioRecordDelegate?
    
    var recorder: AVAudioRecorder?
    var player: AVAudioPlayer?
    
    var maxRecordTime = 60
    
    lazy var audioDir: URL = {
        do {
            
            let urlForUser = AppStatusManager.instance.urlForUser
            let fm = FileManager.default
            let urlForUserAudio = urlForUser!.appendingPathComponent("audio", isDirectory: true)
            try fm.createDirectory(at: urlForUserAudio, withIntermediateDirectories: true, attributes: nil)
            return urlForUserAudio
        } catch {
            print("碰到异常了：\(error.localizedDescription)")
        }
        return URL(string: "")!
    }()
    
    var filePath:URL?
    var fileName:String?
    var hasPermission = true
    
    func setFilePath(path: String) {
        
    }
    
    func isHasPermission() -> Bool{
        let session = AVAudioSession.sharedInstance()
        let microPhone = AVCaptureDevice.authorizationStatus(for: .audio)
        if microPhone == .notDetermined {
            session.requestRecordPermission() { granted in
                if granted {
                    self.hasPermission = true
                } else {
                    self.hasPermission = false
                }
            }
        } else if microPhone != .authorized {
            hasPermission = false
            delegate?.noAudioPermission()
            print("没有麦克风权限")
        }
        return hasPermission
    }
    
    func beginRecord(duration: Int = 100) {
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setCategory(AVAudioSession.Category.record)
            //设置session动作
            try session.setActive(true)
            
            //录音设置，注意，后面需要转换成NSNumber，如果不转换，你会发现，无法录制音频文件，我猜测是因为底层还是用OC写的原因
            let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 8000), //采样率
                AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM), //音频格式
                AVLinearPCMBitDepthKey: NSNumber(value: 16), //采样位数
                AVNumberOfChannelsKey: NSNumber(value: 1), //通道数
                AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.max.rawValue)//录音质量
            ];
            
            
            fileName = NSUUID().uuidString.replacingOccurrences(of:"-",with: "")
            //开始录音
            filePath = audioDir.appendingPathComponent("\(fileName!).wav", isDirectory: false)
            recorder = try AVAudioRecorder(url: filePath!, settings: recordSetting)
            recorder?.isMeteringEnabled = true;
            recorder?.prepareToRecord()
            recorder?.record(forDuration: TimeInterval(maxRecordTime))
            DispatchTimer(timeInterval: duration, stopInFuture: maxRecordTime) { timer in
                self.recorder?.updateMeters()
                let decibels = self.recorder?.averagePower(forChannel: 0)
                self.delegate?.decibels(decibels: decibels ?? -120)
            }
        } catch {
            print("碰到异常了：\(error.localizedDescription)")
        }
    }
    
    func endRecord() {
        if !hasPermission {
            return
        }
        recorder?.stop()
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(false)
            if let tm = timer {
                if !tm.isCancelled {
                    tm.cancel()
                }
            }
            let asset = AVURLAsset(url: filePath ?? audioDir)
            let duration = asset.duration
            let seconds = duration.seconds
            if seconds < 0.6 {
                recorder?.deleteRecording()
                delegate?.recordTooShort()
                //                cancelRecord()
                return
            }
            let amrFilePath = audioDir.appendingPathComponent("\(fileName ?? "failed").amr",isDirectory: false)
            V5VoiceConverter.convertWav(toAmr: filePath?.path ?? "emptyPath", amrSavePath: amrFilePath.path)
            
            delegate?.recordEnd(recordPath: amrFilePath.path,fileName: fileName!, seconds: seconds)
        } catch {
            print("碰到异常了：\(error.localizedDescription)")
        }
    }
    
    func stopRecord() {
        if !hasPermission {
            return
        }
        recorder?.stop()
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(false)
            if let tm = timer {
                if !tm.isCancelled {
                    tm.cancel()
                }
            }
            let asset = AVURLAsset(url: filePath ?? audioDir)
            let duration = asset.duration
            let seconds = duration.seconds
            if seconds < 0.6 {
                recorder?.deleteRecording()
                delegate?.recordTooShort()
                //                cancelRecord()
                return
            }
            _ = audioDir.appendingPathComponent("\(fileName ?? "failed").amr",isDirectory: false)
            delegate?.recordEnd(recordPath: filePath?.path ?? "",fileName: fileName!, seconds: seconds)
        } catch {
            print("碰到异常了：\(error.localizedDescription)")
        }
    }
    
    func convertAudioFile(filePath:URL,to:URL){
        //        let amrFilePath = audioDir.appendingPathComponent("\(fileName ?? "failed").amr",isDirectory: false)
        V5VoiceConverter.convertWav(toAmr: filePath.path, amrSavePath: to.path)
    }
    
    
    
    func cancelRecord() {
        delegate?.recordCanceled()
        if !hasPermission {
            return
        }
        recorder?.stop()
        let audioSession = AVAudioSession.sharedInstance()
        do {
            recorder?.deleteRecording()
            try audioSession.setActive(false)
            if let tm = timer {
                if !tm.isCancelled {
                    tm.cancel()
                }
            }
        } catch {
            print("碰到异常了：\(error.localizedDescription)")
        }
        
    }
    
    func startPlaying(model:ChatMessage) throws {
        let fileName = model.audioPath!
        stopPlay()
        if !(recorder?.isRecording ?? false) {
            let session = AVAudioSession.sharedInstance()
            //            do {
            let wavFilePath = AppStatusManager.instance.urlForUser!.appendingPathComponent("audio", isDirectory: true)
                .appendingPathComponent("\(fileName).wav", isDirectory: false)
            let amrFilePath = AppStatusManager.instance.urlForUser!.appendingPathComponent("audio", isDirectory: true)
                .appendingPathComponent("\(fileName).amr", isDirectory: false)
            //                var data = try Data(contentsOf: url)
            if !FileManager.default.fileExists(atPath: wavFilePath.path) {
                if !FileManager.default.fileExists(atPath: amrFilePath.path) {
//                                            OSSTool.instance.getAudioFile(fileName)
                    FileDownloadTool.instance.download(fileName,onFinish: { (path) in
                        V5VoiceConverter.convertAmr(toWav: amrFilePath.path, wavSavePath: wavFilePath.path)
                        //设置session类型
                        do {
                            try session.setCategory(AVAudioSession.Category.playback)
                            //设置session动作
                            try session.setActive(true)
                            self.player = try AVAudioPlayer(contentsOf: wavFilePath)
                            self.player?.delegate = self
                            _ = self.player?.play()
                            self.delegate?.playBegin(msg: model)
                        }catch {
                            print("\(error.localizedDescription)")
                        }
                        
                    },onError: { (error) in
                        print("\(error.localizedDescription)")
                    })
                }else {
                    V5VoiceConverter.convertAmr(toWav: amrFilePath.path, wavSavePath: wavFilePath.path)
                    do {
                        //设置session类型
                        try session.setCategory(AVAudioSession.Category.playback)
                        //设置session动作
                        try session.setActive(true)
                        player = try AVAudioPlayer(contentsOf: wavFilePath)
                        player?.delegate = self
                        let ss = player!.play()
                        self.delegate?.playBegin(msg: model)
                        print("play!!\(ss)")
                    }catch {
                        print("\(error.localizedDescription)")
                    }
                    
                }
            }else {
                do {
                    //设置session类型
                    try session.setCategory(AVAudioSession.Category.playback)
                    //设置session动作
                    try session.setActive(true)
                    player = try AVAudioPlayer(contentsOf: wavFilePath)
                    player?.delegate = self
                    let ss = player!.play()
                    self.delegate?.playBegin(msg: model)
                    print("play!!\(ss)")
                }catch {
                    print("\(error.localizedDescription)")
                }
            }
            
            //            } catch {
            //                print("\(error.localizedDescription)")
            //            }
        }
    }
    
    func stopPlay() {
        if let player = self.player {
            if player.isPlaying {
                player.stop()
                do {
                    let session = AVAudioSession.sharedInstance()
                    try session.setActive(false)
                    delegate?.playEnd(player.url == nil ? "" : player.url!.path)
                } catch {
                    print("\(error.localizedDescription)")
                }
            }
        }
    }
    
    var timer: DispatchSourceTimer?
    
    func DispatchTimer(timeInterval: Int, stopInFuture: Int, handler: @escaping (DispatchSourceTimer?) -> ()) {
        let queue = DispatchQueue(label: "record.microphone")
        timer = DispatchSource.makeTimerSource(flags: [], queue: queue)
        timer?.schedule(deadline: .now(), repeating: .milliseconds(timeInterval))
        timer?.setEventHandler {
            handler(self.timer)
        }
        timer?.resume()
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(stopInFuture)) {
            if let tm = self.timer {
                if !tm.isCancelled{
                    tm.cancel()
                }
                
            }
        }
    }
    
}

extension AudioRecordUtils : AVAudioPlayerDelegate {
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool){
        do {
            let session = AVAudioSession.sharedInstance()
            try session.setActive(false)
            delegate?.playEnd(player.url == nil ? "" : player.url!.path)
        } catch {
            print("\(error.localizedDescription)")
        }
    }
}
